/*
 * Copyright (c) 2008 ActivCard, Inc., 6623 Dumbarton Circle, Fremont, California 94555 USA.
 * All rights reserved. This document and ActivCard software products are protected by
 * United States copyright laws and international treaty provisions.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.rmi.RemoteException;
import java.util.Properties;

import javax.ejb.CreateException;
import javax.ejb.EJBException;
import javax.naming.InitialContext;
import javax.naming.NamingException;

import com.aspace.ftress.interfaces.ejb.AuthenticatorHome;
import com.aspace.ftress.interfaces.ejb.UserManagerHome;
import com.aspace.ftress.interfaces.ejb.impl.BIAuthenticator;
import com.aspace.ftress.interfaces.ejb.impl.BIUserManager;
import com.aspace.ftress.interfaces.ftress.DTO.*;
//import com.aspace.ftress.utils.SOAP12InterfaceFactory;

/**
 * Multi-threading test client for 4TRESS 3.6 environment.
 * 
 */
public class RMIThreadClientTest36 extends Thread {

	private static transient String SERVER_URL = "";
	private static transient InitialContext ic = null;
	private static transient UserManagerHome userManagerHome = null;
	private static transient AuthenticatorHome authenticatorHome = null;
	
	
	

	private static int THREAD_COUNT = 0; // number of threads
	private static int LOOP_COUNT = 0; // number of runs per thread

	private static String DOMAIN_NAME = "";
	private static SecurityDomain globalDomain = new SecurityDomain();
	private static ALSI globalAlsi;

	private static int DIRECT_USER_POOL_SIZE = 0;
	private static int custCount = 0;

	private static int CREATE_DIRECT_USER_START_NUM = 0;
	private static int NUM_DIRECTUSER_TO_CREATE = 0;

	// Admin User INFO
	private static String ADMIN_USER = "";
	private static String ADMIN_PASSWORD = "";
	private static String ADMIN_CHANNEL_CODE = "";
	private static String ADMIN_AUTH_TYPE = "";

	// direct user info
	private static String DIRECT_USER_GROUP_CODE = "";
	private static String DIRECT_USER_AUTH_TYPE = "";
	private static String DIRECT_USER_CHANNEL_CODE = "";
	private static String DIRECT_USER_PREFIX = "";
	private static String DIRECT_USER_OTP = "";

	public static void main(String[] args) throws Exception {

		if (args.length != 1) {
			System.out.println("$JAVA_HOME/bin/java RMIThreadClientTest36 <path to properties file>");
			System.exit(0);
		}
		File propFile = new File(args[0]);

		FileInputStream fin = new FileInputStream(propFile);
		Properties props = new Properties();
		props.load(fin);

		/*
		 * Populate data based on properties file
		 */

		// populate server URL
		ic = new InitialContext(props);
		
		//Now get a cache the home interfaces before any 
		getUserManagerHome();
		getAuthenticatorHome();


		// populate thread count
		String threadCound = props.getProperty("THREAD_COUNT");
		THREAD_COUNT = Integer.parseInt(threadCound);

		// populate loop count
		String looopCount = props.getProperty("LOOP_COUNT");
		LOOP_COUNT = Integer.parseInt(looopCount);

		// populate domain name
		DOMAIN_NAME = props.getProperty("DOMAIN_NAME");

		// populate direct user pool size
		String directUserPoolSize = props.getProperty("DIRECT_USER_POOL_SIZE");
		DIRECT_USER_POOL_SIZE = Integer.parseInt(directUserPoolSize);

		// populate Admin info
		ADMIN_USER = props.getProperty("ADMIN_USER");
		ADMIN_PASSWORD = props.getProperty("ADMIN_PASSWORD");
		ADMIN_CHANNEL_CODE = props.getProperty("ADMIN_CHANNEL_CODE");
		ADMIN_AUTH_TYPE = props.getProperty("ADMIN_AUTH_TYPE");

		// populate direct user info
		DIRECT_USER_GROUP_CODE = props.getProperty("DIRECT_USER_GROUP_CODE");
		DIRECT_USER_AUTH_TYPE = props.getProperty("DIRECT_USER_AUTH_TYPE");
		DIRECT_USER_CHANNEL_CODE = props
				.getProperty("DIRECT_USER_CHANNEL_CODE");
		DIRECT_USER_PREFIX = props.getProperty("DIRECT_USER_PREFIX");
		DIRECT_USER_OTP = props.getProperty("DIRECT_USER_OTP");

		// direct user start number
		String directUserStatNum = props
				.getProperty("CREATE_DIRECT_USER_START_NUM");
		CREATE_DIRECT_USER_START_NUM = Integer.parseInt(directUserStatNum);

		// number of users to create
		String numUserToCreate = props.getProperty("NUM_DIRECTUSER_TO_CREATE");
		NUM_DIRECTUSER_TO_CREATE = Integer.parseInt(numUserToCreate);

		/*
		 * login to obtain admin global ALSI
		 */
		globalAlsi = loginAdminUP();

		RMIThreadClientTest36 clientTest36 = new RMIThreadClientTest36();

		clientTest36.menu();
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		String choice = br.readLine();

		if (choice.equalsIgnoreCase("x")) {
			System.exit(1);
		} else if (choice.equalsIgnoreCase("d")) {
			clientTest36.createDirectUsers(SERVER_URL, globalAlsi);
			System.exit(1);
		} else {
			for (int i = 0; i < THREAD_COUNT; i++) {
				
				// kick off client calls 
				new RMIThreadClientTest36().start();
			}
		}
	}

	
	private static UserManagerHome getUserManagerHome() throws NamingException {
		if (userManagerHome == null) {			
				userManagerHome = (UserManagerHome)ic.lookup("ejb/4TRESSUserManager");					
		}
		return userManagerHome;		
	}
	
	private static BIUserManager getUserManagerEJB() throws EJBException, RemoteException, CreateException, NamingException {
		return getUserManagerHome().create();
	}
	
	private static BIAuthenticator getAuthenticatorEJB() throws EJBException, RemoteException, CreateException, NamingException {
		return getAuthenticatorHome().create();
	}
	
	private static AuthenticatorHome getAuthenticatorHome() throws NamingException {
		if (authenticatorHome == null) {			
			authenticatorHome = (AuthenticatorHome)ic.lookup("ejb/4TRESSAuthenticator");					
		}
		return authenticatorHome;		
	}


	/**
	 * Create Direct User
	 * 
	 * @param serverURL
	 * @param alsi
	 * @throws Exception
	 */
	public void createDirectUsers(String serverURL, ALSI alsi) throws Exception {

		int numberUserCreated = 0;
		for (int i = CREATE_DIRECT_USER_START_NUM; i < (CREATE_DIRECT_USER_START_NUM + NUM_DIRECTUSER_TO_CREATE); i++) {
			String userCodeName = DIRECT_USER_PREFIX + i;
			User user = this.create4TUser(alsi, userCodeName,
					DIRECT_USER_GROUP_CODE);

			numberUserCreated++;
		}
		System.out.println(numberUserCreated
				+ " direct users creation completed");
	}

	/**
	 * Create 4TRESS user.
	 * 
	 * @param serverURL
	 * @param alsi
	 * @param userCodeName
	 * @param groupCodeValue
	 * @return
	 * @throws Exception
	 */
	public User create4TUser(ALSI alsi, String userCodeName,
			String groupCodeValue) throws Exception {

		ChannelCode channelCode = new ChannelCode();
		channelCode.setCode(ADMIN_CHANNEL_CODE);

		UserCode userCode = new UserCode(userCodeName);
		User user = new User();
		user.setCode(userCode);
		GroupCode groupCode = new GroupCode();
		groupCode.setCode(groupCodeValue);
		user.setGroupCode(groupCode);
		user.setStartDate(java.util.Calendar.getInstance());
		user.setStatus("ENABLED");

		BIUserManager userManager = getUserManagerEJB();

		globalDomain.setDomain(DOMAIN_NAME);

		user = userManager.createUser(alsi, channelCode, user, globalDomain);

		return user;

	}




	public synchronized int getCustomerNumber() {
		int n = custCount % DIRECT_USER_POOL_SIZE + 1;
		custCount++;
		return n;
	}

	public void menu() {
		System.out.println(" ***** Thread Test 4TRESS 3.6.2 ***** \n");
		System.out.println("d. create direct users utility");
		System.out.println("x. Exit ");
		System.out.println("ENTER to procdeed with multi-threading test");
		System.out.print("input:");
	}

	public void run() {

		try {
			int i = 0;
			long t1 = 0;
			long t2 = 0;

			// create req
			DeviceAuthenticationRequest activrequest = new DeviceAuthenticationRequest();
			activrequest
					.setAuthenticationMode(DeviceAuthenticationRequest.SYNCHRONOUS);
			activrequest.setAuthenticationTypeCode(new AuthenticationTypeCode(
					DIRECT_USER_AUTH_TYPE));
			activrequest.setUserCode(new UserCode(DIRECT_USER_PREFIX
					+ this.getCustomerNumber()));
			activrequest.setOneTimePassword(DIRECT_USER_OTP);// bogus OTP

			t1 = System.currentTimeMillis();

			ChannelCode channelCode = new ChannelCode();

			channelCode.setCode(DIRECT_USER_CHANNEL_CODE);

			BIAuthenticator ftressAuthenticator = getAuthenticatorEJB();

			for (i = 0; i <= LOOP_COUNT; i++) {

				SecurityDomain domain = new SecurityDomain();
				domain.setCode(DOMAIN_NAME);

				AuthenticationResponse resp = null;
				try {
					resp = ftressAuthenticator.primaryAuthenticateDevice(
							channelCode, activrequest, domain);
				} catch (Exception e) {
					e.printStackTrace();
				}

				t2 = System.currentTimeMillis();

				System.out.println(super.getName() + ": Message   :  "
						+ resp.getMessage());
				System.out.println(super.getName() + ": Count   :  " + i);
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}




	public synchronized static ALSI getGlobalALSI() {
		return globalAlsi;
	}

	/**
	 * Login and retrieve admin ALSI
	 * 
	 * @param serverURL
	 * @return
	 * @throws Exception
	 */
	public static ALSI loginAdminUP() throws Exception {
		try {
			ChannelCode channelCode = new ChannelCode();
			channelCode.setCode(ADMIN_CHANNEL_CODE);
			AuthenticationTypeCode atCode = new AuthenticationTypeCode();
			atCode.setCode(ADMIN_AUTH_TYPE);

			UPAuthenticationRequest upAuthenticationRequest = new UPAuthenticationRequest();
			upAuthenticationRequest.setUsername(ADMIN_USER);
			upAuthenticationRequest.setPassword(ADMIN_PASSWORD);
			upAuthenticationRequest.setAuthenticationTypeCode(atCode);

			BIAuthenticator ftressAuthenticator = getAuthenticatorEJB();
			globalDomain.setDomain(DOMAIN_NAME);
			AuthenticationResponse response = ftressAuthenticator
					.primaryAuthenticateUP(channelCode,
							upAuthenticationRequest, globalDomain);
			System.out.println("Admin obtained global ALSI:" + (response.getResponse() == 1));
			// 1 = success, 2 = failure
			return response.getAlsi();

		} catch (Exception e) {

			System.out.println("loginUP caused exception");
			e.printStackTrace();

			return null;
		}

	}

}
